﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Text.RegularExpressions;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

using Bitmap = System.Drawing.Bitmap;
using Rect = System.Drawing.Rectangle;
using SColor = System.Drawing.Color;
using LuaInterface;

namespace LeagueOverlay
{

    /*
     * This gathers all the champion data from the LoadScreen by capturing the loadscreen as an image and
     * processing that into champions and summoner spells 
     */
    public class LeagueInfo
    {
        
        ScriptControl sc = new ScriptControl(null);
        public static string heroName = "";
        public static int currentLevel = 0;
        //static int healthPixCount = -1; // Disregard these, they're in development
        /*
         * Champion spell cooldown info, in this order: Q, W, E, R, Summoner Spell 1, Summoner Spell 2.
         * */
        public static int[] spellCooldowns = new int[6] { 0, 0, 0, 0, 0, 0 };
        public static Bitmap[] spellBitmaps = new Bitmap[6] { null, null, null, null, null, null }; 

        public static double healthPercent=100;  // ^^^^
        
        public MainWindow form;
        public static Dictionary<string, string> cnames = new Dictionary<string, string>();

        DateTime lastUpdate = DateTime.Now;

        public bool outOfLoadScreen = false;
        Bitmap currentLevelImage = null;
        byte[] currentImgBytes = new byte[1];
        LoadScreenInfo loadScreenInfo = null;

        SummonerInfo[][] summonerInfo = new SummonerInfo[2][];

        Dictionary<string, SummonerSpellInfo> summonerSpellInfo = new Dictionary<string, SummonerSpellInfo>();

        // This is a fallback for cNames (it should have been used in the first place to deal with spaced names
        // like "Master Yi" and "Xin Zhao"
        Dictionary<string, string> championNameMap = new Dictionary<string,string>();

        //Some classes (aka structs)
        class SummonerInfo
        {
            public string championCodeName;
            public string summonerSpell1;
            public string summonerSpell2;
        }
        class SummonerSpellInfo
        {
            public string codeName;
            public string name;
            public int cooldown;
            public Bitmap image;
        }

        class LoadScreenInfo
        {
            public int
                minX,
                maxX,
                minY,
                maxY,
                minXBot,
                maxXBot,
                topChampionCount,
                botChampionCount,
                championWidth,
                championHeight,
                xpadding,
                topPadding;
            public double scale;
        }
        public class ChampNameAndImage
        {
            public string codeName;
            public Bitmap image;
        }

        List<ChampNameAndImage> champData = new List<ChampNameAndImage>();


        /*
         * Loads all the summoner spell names/images and champion names/images
         * for reference in order to process the load screen
         */
        public LeagueInfo(MainWindow f)
        {
            try
            {
                // Load the backup champion name map
                string[] fileLines = File.ReadAllLines(LeagueUtils.FileFinder.fontConfigFinder());
                foreach (string line in fileLines)
                {
                    //An example of the line we're looking for: tr "game_character_displayname_Akali" = "Akali"
                    if (line.Contains("game_character_displayname"))
                    {
                        string baseName = line.Replace("tr \"game_character_displayname_", "");
                        int i = baseName.LastIndexOf("=") + 3;
                        string mappedname = baseName.Substring(i, baseName.Length - i - 1);
                        baseName = baseName.Substring(0, baseName.IndexOf("\"")).ToLower();
                        championNameMap.Add(baseName, mappedname);
                    }
                }
                form = f;

                //init summoner spell info table
                SummonerSpellInfo ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerBoost";
                ssi.name = "Cleanse";
                ssi.cooldown = 130;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerClairvoyance";
                ssi.name = "Clairvoyance";
                ssi.cooldown = 55;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerDot";
                ssi.name = "Ignite";
                ssi.cooldown = 120;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerExhaust";
                ssi.cooldown = 210;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerFlash";
                ssi.name = "Flash";
                ssi.cooldown = 225;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerFortify";
                ssi.name = "Fortify";
                ssi.cooldown = 300;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerHaste";
                ssi.name = "Ghost";
                ssi.cooldown = 210;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerHeal";
                ssi.name = "Heal";
                ssi.cooldown = 270;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerMana";
                ssi.name = "Clarity";
                ssi.cooldown = 180;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerPromote";
                ssi.name = "Promote";
                ssi.cooldown = 300;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerRally";
                ssi.name = "Rally";
                ssi.cooldown = 360;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerRevive";
                ssi.name = "Revive";
                ssi.cooldown = 520;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerSmite";
                ssi.name = "Smite";
                ssi.cooldown = 75;
                summonerSpellInfo[ssi.codeName] = ssi;

                ssi = new SummonerSpellInfo();
                ssi.codeName = "Spell_SummonerTeleport";
                ssi.name = "Teleport";
                ssi.cooldown = 240;
                summonerSpellInfo[ssi.codeName] = ssi;

                // Load the summoner spell images
                foreach (string key in summonerSpellInfo.Keys)
                {
                    summonerSpellInfo[key].image = (Bitmap)Image.FromFile(LeagueUtils.FileFinder.findSummonerSpells() + "\\" + key + ".png");
                }

                // Match strings similar to ""<word(s)>_<word(s)>""=""
                Regex r = new Regex(@"""(\w+)_(\w+)"" = ""([^""]+)");
                foreach (string s in File.ReadAllLines(LeagueUtils.FileFinder.fontConfigFinder()))
                {
                    Match m = r.Match(s);
                    if (m.Success)
                    {
                        string infoType = m.Groups[1].Value;
                        string infoID = m.Groups[2].Value;
                        string infoValue = m.Groups[3].Value;
                        if (infoType == "game_character_displayname" &&
                            File.Exists(LeagueUtils.FileFinder.findChampImageFolder() + "\\" + infoID + "_Square_0.png"))
                            cnames.Add(infoID, infoValue);
                    }
                }

                //get champion images for load screen processing
                foreach (FileInfo fi in new DirectoryInfo(LeagueUtils.FileFinder.findChampImageFolder()).GetFiles("*.jpg"))
                {
                    if (fi.Name.ToLower().Contains("_square_") || fi.Name.ToLower().Contains("_splash_") || fi.Name.Count(c => c == '_') != 1) continue;
                    ChampNameAndImage champ = new ChampNameAndImage();
                    champ.codeName = fi.Name.Split('_')[0];
                    champ.image = (Bitmap)Bitmap.FromFile(fi.FullName);
                    champData.Add(champ);
                }
                fileLines = null;
            }
            catch (Exception e)
            {
                sc.log("[ERROR] (" + e.Source + "): " + e.Message + "\n" + e.StackTrace);
                throw;
            }

        }

        //do update league info
        public void update()
        {
            try
            {
                Bitmap screenCap = (Bitmap)form.windowImage.Clone();
                if (form.windowImage.Width < 10 || form.windowImage.Height < 10)
                {
                    return;
                }
                /*look for the load screen*/
                if (!outOfLoadScreen)
                {
                    var w = form.windowImage;
                    bool allBlack = true;
                    for (int x = w.Width / 2; x < w.Width; x++)
                    {
                        for (int y = w.Height - 5; y < w.Height; y++)
                        {
                            var c = w.GetPixel(x, y);
                            if (c.R != 0 || c.G != 0 || c.B != 0)
                            {
                                allBlack = false;
                                break;
                            }
                        }
                    }
                    if (allBlack) //process the load screen
                    {
                        if (loadScreenInfo == null) //process the loadscreen for the first time.
                        {
                            parseLoadingScreen();
                            return;
                        }

                        /*
                         * If the load screen has been processed, interpret the information in
                         * loadScreenInfo and write it to the summonerInfo array as well as the log
                         */
                        for (int i = 0; i < loadScreenInfo.topChampionCount; i++) // Top row of champions
                        {
                            if (summonerInfo[0][i] == null)
                            {
                                summonerInfo[0][i] = getSummonerInfo(
                                    (Bitmap)w,
                                    loadScreenInfo.minX + i * (loadScreenInfo.championWidth + loadScreenInfo.xpadding) - 1,
                                    loadScreenInfo.topPadding,
                                    loadScreenInfo.scale,
                                    i);
                                if (summonerInfo[0][i] == null)
                                {
                                    //form.scriptControl.log("System Exit");
                                    //System.Environment.Exit(1);
                                    //update();
                                    return;
                                }
                                else
                                    form.scriptControl.log("LoadScreen: Found top champion (" + summonerInfo[0][i].championCodeName + ") with " + summonerInfo[0][i].summonerSpell1 + " and " + summonerInfo[0][i].summonerSpell2);
                            }
                        }

                        for (int i = 0; i < loadScreenInfo.botChampionCount; i++) // Bottom row of champions
                        {
                            if (summonerInfo[1][i] == null)
                            {
                                summonerInfo[1][i] = getSummonerInfo(
                                    (Bitmap)w,
                                    loadScreenInfo.minXBot + i * (loadScreenInfo.championWidth + loadScreenInfo.xpadding) - 1,
                                    w.Height - loadScreenInfo.topPadding - loadScreenInfo.championHeight - 2,
                                    loadScreenInfo.scale,
                                    i + 5);
                                if (summonerInfo[1][i] == null)
                                {
                                    //form.scriptControl.log("System Exit");
                                    //System.Environment.Exit(1);
                                    //update();
                                    return;
                                }
                                else
                                    form.scriptControl.log("LoadScreen: Found bot champion (" + summonerInfo[1][i].championCodeName + ") with " + summonerInfo[1][i].summonerSpell1 + " and " + summonerInfo[1][i].summonerSpell2);
                            }
                        }
                        return;
                    }

                    else  //in game now
                    {
                        form.scriptControl.raiseEvent("interfaceInit", "");
                        outOfLoadScreen = true;
                        form.scriptControl.log("Left Load Screen");
                        foreach (var v in champData)
                        {
                            v.image.Dispose();
                            v.image = null;
                            //Empty the champion data from the load screen
                        }
                    }
                }

                /* Set Current Hero Name */

                if (heroName == "")
                {
                    string curName = "";
                    double curRMS = double.MaxValue;
                    double rms = 0;
                    Bitmap bit, temp;
                    temp = screenCap.Clone(LeagueUI.playerAvatar, System.Drawing.Imaging.PixelFormat.Undefined);
                    Bitmap cBit = new Bitmap(temp, new System.Drawing.Size(120, 120));
                    temp.Dispose();
                    Rectangle r = new System.Drawing.Rectangle((int)(cBit.Width * (20.0 / 120.0)), (int)(cBit.Height * (20.0 / 120.0)), (int)(cBit.Width * (68.0 / 120.0)), (int)(cBit.Height * (72.0 / 120.0)));
                    temp = cBit;
                    cBit = cBit.Clone(r, System.Drawing.Imaging.PixelFormat.Undefined);
                    temp.Dispose();
                    cBit.Save("championInfo\\champion.png");
                    // loop through heroes and find the one with the lowest rms diff.
                    foreach (string c in cnames.Keys)
                    {
                        temp = new Bitmap(LeagueUtils.FileFinder.findChampImageFolder() + "\\" + c + "_Square_0.png");
                        bit = temp.Clone(r, System.Drawing.Imaging.PixelFormat.Undefined);
                        temp.Dispose();

                        if (c.ToLower() == "garen") bit.Save("championInfo\\garen.png");
                        rms = calcRMSDiff(cBit, bit);
                        bit.Dispose();
                        if (rms < curRMS)
                        {
                            curRMS = rms;
                            curName = c;
                        }
                        bit.Dispose();
                        //  System.Diagnostics.Debug.WriteLine(cnames[i] + " " + rms);

                    }
                    cBit.Dispose();
                    heroName = curName;
                    //bit = new Bitmap(Preferences.leagueFolder + "\\air\\assets\\images\\champions\\" + heroName + "_Square_0.png");

                    System.Diagnostics.Debug.WriteLine("Hero Name" + heroName);
                    form.scriptControl.log("Player Champion: " + heroName);
                }

                /* End Setting Hero Name */

                /**********************************************************************/

                /* Set Current Hero Level */
                //int thinkLevel = 1;
                Bitmap wLevelBit, unResizedLevelBit;
                byte[] newImgBytes = new byte[1];
                ImageConverter converter = new ImageConverter();
                //System.Diagnostics.Debug.WriteLine(LeagueUI.cLevel);
                unResizedLevelBit = screenCap.Clone(LeagueUI.cLevel, System.Drawing.Imaging.PixelFormat.Undefined);
                wLevelBit = new Bitmap(unResizedLevelBit, new System.Drawing.Size(12, 8));
                wLevelBit.Save("championInfo\\LEVEL_IMAGE.png");
                unResizedLevelBit.Dispose();
                /*if (firstLoad)
                {
                    currentLevelImage = wLevelBit;
                    currentImgBytes = (byte[])converter.ConvertTo(currentLevelImage, currentImgBytes.GetType()); 
                    currentLevel++;
                    System.Diagnostics.Debug.WriteLine("Hero Level" + currentLevel);
                    form.scriptControl.levelUp();
                    firstLoad = false;
                }*/
                newImgBytes = (byte[])converter.ConvertTo(wLevelBit, newImgBytes.GetType());
                for (int i = 0; i < currentImgBytes.Length && i < newImgBytes.Length; i++)
                {
                    if (!(currentImgBytes[i] == newImgBytes[i]) && currentLevel < 18)
                    {
                        currentLevel++;
                        System.Diagnostics.Debug.WriteLine("Hero Level" + currentLevel);
                        form.scriptControl.levelUp();
                        currentLevelImage = wLevelBit;
                        currentImgBytes = (byte[])converter.ConvertTo(currentLevelImage, currentImgBytes.GetType());
                    }
                }

                wLevelBit.Dispose();
                /* End Setting Hero Level*/
                /*Bitmap testBit = null;
                testBit = (Bitmap) form.windowImage.Clone();
                testBit.Save("championInfo\\ScreenCap" + DateTime.Now.Second.ToString() + ".png");
                testBit.Dispose();*/
                /* Hero Abilities */
                /*
                 *  Threshold for deciding when an ability is considered to be on cooldown, needs to be high enough to avoid false positives like with
                 *  Clarity (large amount of blue pixels) and low enough to allow long cooldown abilities to be counted (like with 3-digit white text)
                 */
                int cooldownThreshold = 300;
                Bitmap wAbilityBit, unResizedAbilityBit;
                /*
                 * Cycle through the abilitiy rectangles and get the image from the screen cap saved at the start of the loop.
                 * Save the bitmap into the bitmap array.
                 * Look at each pixel and decide if its blue or a light shade of grey/white, then tally it to the variable blueCount
                 * If bluecount is greater than the cooldownThreshold, then its considered to be on cooldown.
                 * Dispose of the bitmap and continue on to the next one.
                 */
                for (int i = 0; i < 6; i++)
                {
                    unResizedAbilityBit = screenCap.Clone(LeagueUI.spellRect[i], System.Drawing.Imaging.PixelFormat.Undefined);
                    spellBitmaps[i] = new Bitmap(unResizedAbilityBit, new System.Drawing.Size(unResizedAbilityBit.Width * 2, unResizedAbilityBit.Height * 2));
                    //unResizedAbilityBit.Save("scripts\\Images\\ability_" + i + ".png");
                    wAbilityBit = new Bitmap(unResizedAbilityBit, new System.Drawing.Size(20, 20));
                    //wAbilityBit.Save("championInfo\\Ability_" + i + ".png");
                    int blueCount = 0;
                    for (int y = 0; y < wAbilityBit.Height; y++)
                    {
                        for (int x = 0; x < wAbilityBit.Width; x++)
                        {
                            var c = wAbilityBit.GetPixel(x, y);
                            if ((c.B >= c.G + 50 && c.B >= c.R + 50) || (c.R > 140 && c.B > 140 && c.G > 140)) blueCount++;
                        }
                    }
                    //wAbilityBit.Save("championInfo\\BlueCount-" + blueCount.ToString() + ".png");
                    unResizedAbilityBit.Dispose();
                    wAbilityBit.Dispose();
                    if (blueCount >= cooldownThreshold)
                    {
                        spellCooldowns[i] = 1;
                        //sc.log("blueCount " + i + ": " + blueCount);
                    }
                    else
                        spellCooldowns[i] = 0;
                }
                /*********************************************************************/

                /* Set Available Abilities */
                //  System.Diagnostics.Debug.WriteLine(canChooseAbility[0] + " " + canChooseAbility[1] + " " + canChooseAbility[2] + " " + canChooseAbility[3]);
                /* End Setting Available Abilities */

                /*********************************************************************/

                /* Set Health Percent */
                /*
                Bitmap hBit = form.windowImage.Clone(LeagueUI.cHealth, System.Drawing.Imaging.PixelFormat.Undefined);
                SColor hColor;
                int hCount = 0;
                for (int i = 0; i < hBit.Width; i++)
                {
                    for (int j = 0; j < hBit.Height; j++)
                    {
                        hColor = hBit.GetPixel(i, j);
                        if (hColor.G > 100 && hColor.R < 100 && hColor.B < 100)
                            hCount++;

                    }
                }
            
                if (healthPixCount == -1)
                {
                    healthPercent = 100.0;
                    healthPixCount = hCount;
                }
                else
                {
                    healthPercent = (double)hCount / (double)healthPixCount;
                }
                 * */
                //System.Diagnostics.Debug.WriteLine("health percent" + healthPercent);
                /* Set Mana/Energy Percent */


                lastUpdate = DateTime.Now;
            }
            catch (Exception e)
            {
                sc.log("[ERROR] (" + e.Source + "): " + e.Message + "\n" + e.StackTrace);
                throw;
            }
            
        }

        // Returns the hero level
        [AttrLuaFunc("GetHeroLevel")]
        public static int getHeroLevel()
        {
            return currentLevel;
        }

        // Returns the player's champion name derived from the ingame champion square
        [AttrLuaFunc("GetHeroName")]
        public static string getHeroName()
        {
            return heroName;
        }

        // Returns the champions health percentage
        [AttrLuaFunc("GetHealthPercent")]
        public static double getHealthPercent()
        {
            return healthPercent;
        }

        // Returns 1 if given spell numer is on cooldown. Else it returns 0.
        [AttrLuaFunc("GetSpellCooldown")]
        public static int getSpellCooldown(int i)
        {
            if (i <= 5)
                return spellCooldowns[i];
            else
                return 0;
        }

        // For now, this dumps the given spell image into scripts\\Images\\.
        [AttrLuaFunc("DumpSpellImage")]
        public static void dumpSpellImage(int abilityNumber)
        {
            if(abilityNumber > 5)
                return;
            try
            {
                File.Delete("scripts\\Images\\ability_" + abilityNumber + ".png");
                spellBitmaps[abilityNumber].Save("scripts\\Images\\ability_" + abilityNumber + ".png");
            }
            catch (Exception e)
            {
            }
        }

        [AttrLuaFunc("GetSpellImage")]
        public static Bitmap getSpellImage(int abilityNumber)
        {
            try
            {
                return spellBitmaps[abilityNumber];
            }
            catch (Exception e)
            {
                return null;
            }
        }

        // Returns a value representing the difference between 2 images. 1 means the images are identical
        public double calcRMSDiff(Bitmap r, Bitmap b)
        {
            double s = 0;
            if (r.Width != b.Width || r.Height != b.Height) return double.MaxValue;
            var rInfo = r.LockBits(new Rectangle(0, 0, r.Width, r.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            var bInfo = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* rStart = (byte*)rInfo.Scan0;
                byte* bStart = (byte*)bInfo.Scan0;

                for (int i = 0; i < rInfo.Stride * rInfo.Height; i++)
                {
                    int temp = bStart[i] - rStart[i];
                    s += temp * temp;
                }
            }
            r.UnlockBits(rInfo);
            b.UnlockBits(bInfo);
            return (1 / ((double)(r.Height * r.Width))) * s;
        }

        public double calcRMSDiff(Bitmap r, Bitmap b, Rectangle rect)
        {
            if (rect.Right > b.Width || rect.Height > b.Height || rect.X > b.Width || rect.Y > b.Height) return double.MaxValue;
            double sum = 0;
            var rInfo = r.LockBits(new Rectangle(0, 0, r.Width, r.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            var bInfo = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* rStart = (byte*)rInfo.Scan0;
                byte* bStart = (byte*)bInfo.Scan0;

                for (int y = rect.Y; y <= rect.Y + rect.Height; y++)
                {
                    for (int x = rect.X; x <= rect.X + rect.Width; x++)
                    {
                        int redD = bStart[x + y * bInfo.Stride] - rStart[x + y * rInfo.Stride];
                        int greenD = bStart[x + y * bInfo.Stride + 1] - rStart[x + y * rInfo.Stride + 1];
                        int blueD = bStart[x + y * bInfo.Stride + 2] - rStart[x + y * rInfo.Stride + 2];

                        sum += redD * redD + greenD * greenD + blueD * blueD;
                    }
                }
            }
            r.UnlockBits(rInfo);
            b.UnlockBits(bInfo);

            return (1 / ((double)(r.Height * r.Width))) * sum;

        }

        //two byte arrays
        public double calcRMSDiff(byte []  rBytes, byte[] bBytes)
        {
           
            double sum = 0;
            int w = 12;
            int h = 8;

            for (int i = 0; i < LeagueUI.levelBitSize; i++)
            {
                sum += Math.Pow(rBytes[i] - bBytes[i], 2);
            }

            return (1 / ((double)(h * w))) * sum;

        }

        // Returns the number of players on a given team (0 = Blue, 1 = Purple)
        [AttrLuaFunc("GetSummonerCount")]
        public int getSummonerCount(int team)
        {
            if (summonerInfo[team] == null) return 0;
            return summonerInfo[team].Length;
        }

        // Returns the given LuaTable with the champion from the given team and index
        [AttrLuaFunc("GetSummonerInfo")]
        public LuaTable getSummonerInfo(int team, int summoner, LuaTable infoTable)
        {
            if (summonerInfo[team] == null || summonerInfo[team][summoner] == null)
            {
                infoTable["championName"] = "Ashe";
                infoTable["championCodeName"] = "Bowmaster";

                infoTable["spell1CodeName"] = "Spell_SummonerBoost";
                infoTable["spell1Name"] = "Cleanse";
                infoTable["spell1Cooldown"] = 10;

                infoTable["spell2CodeName"] = "Spell_SummonerDot";
                infoTable["spell2Name"] = "Ignite";
                infoTable["spell2Cooldown"] = 10;
            }
            else
            {
                SummonerInfo si = summonerInfo[team][summoner];

                if (cnames.ContainsKey(si.championCodeName))
                    infoTable["championName"] = cnames[si.championCodeName];
                else if (championNameMap.ContainsKey(si.championCodeName.ToLower()))
                    infoTable["championName"] = championNameMap[si.championCodeName.ToLower()];//"Bad Name";
                else
                    infoTable["championName"] = "Bad Name";
                infoTable["championCodeName"] = si.championCodeName;

                infoTable["spell1CodeName"] = si.summonerSpell1;
                if (summonerSpellInfo.ContainsKey(si.summonerSpell1))
                {
                    infoTable["spell1Name"] = summonerSpellInfo[si.summonerSpell1].name;
                    infoTable["spell1Cooldown"] = summonerSpellInfo[si.summonerSpell1].cooldown;
                }
                else
                {
                    infoTable["spell1Name"] = "??";
                    infoTable["spell1Cooldown"] = 10;
                }

                infoTable["spell2CodeName"] = si.summonerSpell2;
                if (summonerSpellInfo.ContainsKey(si.summonerSpell2))
                {
                    infoTable["spell2Name"] = summonerSpellInfo[si.summonerSpell2].name;
                    infoTable["spell2Cooldown"] = summonerSpellInfo[si.summonerSpell2].cooldown;
                }
                else
                {
                    infoTable["spell2Name"] = "??";
                    infoTable["spell2Cooldown"] = 10;
                }
            }
            return infoTable;
        }

        /*
         * This scans the loading screen image untill it finds a pixel which is not black. Then it
         * starts from the middle of the image (that is, the middle height wise) and works upwards until it finds
         * a black pixel, denoting a safe bottom point of the champion image.
         * 
         * Then, starting from the safe bottom point, it starts upwards again untill it finds a pixel that is non-black
         * and notes the location of the pixel in the y frame.
         * 
         * It then captures that area with a rectangle using the start point and the known bottom point.
         */
        public void parseLoadingScreen()
        {
            try
            {
                Image b = form.windowImage;
                loadScreenInfo = new LoadScreenInfo();
                LoadScreenInfo lsi = loadScreenInfo;

                lsi.minX = b.Width - 1;
                lsi.maxX = 0;
                lsi.minXBot = b.Width - 1;
                lsi.maxXBot = 0;

                bool foundNonBlack = false;
                for (int x = 5; x < b.Width - 5; x++)
                {
                    var c = ((Bitmap)b).GetPixel(x, b.Height / 4);
                    if (c.B != 0 || c.R != 0 || c.G != 0)
                    {
                        if (x < lsi.minX) lsi.minX = x;
                        if (x > lsi.maxX) lsi.maxX = x;
                        foundNonBlack = true;
                    }
                    c = ((Bitmap)b).GetPixel(x, 3 * b.Height / 4);
                    if (c.B != 0 || c.R != 0 || c.G != 0)
                    {
                        if (x < lsi.minXBot) lsi.minXBot = x;
                        if (x > lsi.maxXBot) lsi.maxXBot = x;
                    }
                }

                if (lsi.minX >= lsi.maxX || lsi.minXBot >= lsi.maxXBot || !foundNonBlack)
                {
                    loadScreenInfo = null;
                    return;
                }

                //find a safe bottom point
                int bot = b.Height / 2;
                for (int y = b.Height / 2; y >= 0; y--)
                {
                    var c = ((Bitmap)b).GetPixel(lsi.minX + 20, y);
                    if (c.B == 0 && c.R == 0 && c.G == 0)
                    {
                        bot = y;
                        break;
                    }
                }

                //get the champion heights
                lsi.minY = b.Height - 1;
                lsi.maxY = 0;
                for (int y = 5; y < bot; y++)
                {
                    var c = ((Bitmap)b).GetPixel(lsi.minX + 20, y);
                    if (c.B != 0 || c.R != 0 || c.G != 0)
                    {
                        if (y < lsi.minY) lsi.minY = y;
                        if (y > lsi.maxY) lsi.maxY = y;
                    }
                }

                if (lsi.minY >= lsi.maxY)
                {
                    loadScreenInfo = null;
                    return;
                }


                lsi.scale = (lsi.maxY - lsi.minY) / 341.0;

                lsi.topChampionCount = (int)((lsi.maxX - lsi.minX) / (185 * lsi.scale - 5));
                lsi.botChampionCount = (int)((lsi.maxXBot - lsi.minXBot) / (185 * lsi.scale - 5));

                if (lsi.topChampionCount <= 0 || lsi.botChampionCount <= 0)
                {

                    loadScreenInfo = null;
                    return;
                }

                lsi.championWidth = (int)Math.Round(190 * lsi.scale);
                lsi.championHeight = (int)Math.Round(341 * lsi.scale);
                lsi.xpadding = (int)Math.Round(10 * lsi.scale);
                lsi.topPadding = lsi.minY;


                //System.Diagnostics.Debug.WriteLine("Top champions:" + lsi.topChampionCount);
                //System.Diagnostics.Debug.WriteLine("Bottom champions:" + lsi.botChampionCount);
                summonerInfo[0] = new SummonerInfo[lsi.topChampionCount];
                summonerInfo[1] = new SummonerInfo[lsi.botChampionCount];

                form.scriptControl.log("LoadScreen: " + lsi.topChampionCount + " (top) " + lsi.topChampionCount + " (bot)");
            }
            catch (Exception e)
            {
                sc.log("[ERROR] (" + e.Source + "): " + e.Message + "\n" + e.StackTrace);
                throw;
            }
        }

        /*
         * This processes the raw images given by parseLoadingScreen()
         */
        SummonerInfo getSummonerInfo(Bitmap screenImage, int left, int top, double scale, int champNumber)
        {
            try
            {
                SummonerInfo si = new SummonerInfo();
                Bitmap champImg, sSpell1, sSpell2, temp;
                double minRMS1 = double.MaxValue;
                double minRMS2 = double.MaxValue;
                //Rounding seems to be slightly off when processing the 5th summoner so I'm trying Ceiling/Floor rounding instead
                //Rect spell1Rect = new Rectangle(left + (int)Math.Round(72 * scale), top + (int)Math.Round(298 * scale), (int)Math.Round(23 * scale), (int)Math.Round(24 * scale));
                Rect spell1Rect = new Rectangle(left + (int)Math.Floor(72 * scale), top + (int)Math.Ceiling(298 * scale), (int)Math.Round(23 * scale), (int)Math.Round(24 * scale));
                //check the color on sSpell1 if it is black summoner is not connected
                if (spell1Rect.Right >= screenImage.Width || spell1Rect.Bottom >= screenImage.Height) return null;
                int blackCount = 0;
                for (int y = spell1Rect.Y; y <= spell1Rect.Y + spell1Rect.Height; y++)
                {
                    for (int x = spell1Rect.X; x <= spell1Rect.X + spell1Rect.Width; x++)
                    {
                        var c = screenImage.GetPixel(x, y);
                        if (c.R < 20 && c.G < 20 && c.B < 20) blackCount++;
                    }
                }
                //form.scriptControl.log("Black Count: " + blackCount);
                if (blackCount >= ((spell1Rect.Width * spell1Rect.Height) * 0.7)) return null;
                try
                {
                    champImg = screenImage.Clone(new Rectangle(left, top, (int)Math.Round(185 * scale), (int)Math.Round(305 * scale)), System.Drawing.Imaging.PixelFormat.DontCare);
                    sSpell1 = screenImage.Clone(spell1Rect, System.Drawing.Imaging.PixelFormat.DontCare);

                    //Rounding seems to be slightly off when processing the 5th summoner so I'm trying Ceiling/Floor rounding instead
                    //sSpell2 = screenImage.Clone(new Rectangle(left + (int)Math.Round(99 * scale), top + (int)Math.Round(298 * scale), (int)Math.Round(23 * scale), (int)Math.Round(24 * scale)), System.Drawing.Imaging.PixelFormat.DontCare);
                    sSpell2 = screenImage.Clone(new Rectangle(left + (int)Math.Floor(99 * scale), top + (int)Math.Ceiling(298 * scale), (int)Math.Round(23 * scale), (int)Math.Round(24 * scale)), System.Drawing.Imaging.PixelFormat.DontCare);
                    champImg.Save("./LoadScreen/champ" + champNumber + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
                    sSpell1.Save("./LoadScreen/champ" + champNumber + "Spell1.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
                    sSpell2.Save("./LoadScreen/champ" + champNumber + "Spell2.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
                }
                catch
                {
                    return null;
                }


                temp = sSpell1;
                sSpell1 = new Bitmap(sSpell1, 64, 64);
                temp.Dispose();
                temp = sSpell2;
                sSpell2 = new Bitmap(sSpell2, 64, 64);
                temp.Dispose();
                foreach (KeyValuePair<string, SummonerSpellInfo> kvp in summonerSpellInfo)
                {
                    temp = kvp.Value.image;
                    double rms = calcRMSDiff(sSpell1, temp);
                    if (rms < minRMS1)
                    {

                        si.summonerSpell1 = kvp.Key;
                        minRMS1 = rms;
                    }
                    rms = calcRMSDiff(sSpell2, temp);
                    if (rms < minRMS2)
                    {
                        si.summonerSpell2 = kvp.Key;
                        minRMS2 = rms;
                    }
                }
                //Added this because somehow they can end up being null (no keys in summonerSpellInfo??)
                if (si.summonerSpell1 == null || si.summonerSpell2 == null)
                {
                    sSpell1.Dispose();
                    sSpell2.Dispose();
                    champImg.Dispose();
                    return null;
                }
                System.Diagnostics.Debug.WriteLine("S1 = " + si.summonerSpell1 + " minrms of" + minRMS1);
                System.Diagnostics.Debug.WriteLine("S2 = " + si.summonerSpell2);

                double minChampionRMS = double.MaxValue;
                temp = champImg;
                champImg = new Bitmap(champImg, 307, 557);
                temp.Dispose();

                Rectangle compareRect = new Rectangle(0, 0, 307, 100);
                foreach (ChampNameAndImage champ in champData)
                {
                    temp = champ.image;
                    double rms = calcRMSDiff(champImg, temp, compareRect);
                    if (rms < minChampionRMS)
                    {
                        si.championCodeName = champ.codeName;
                        minChampionRMS = rms;
                        //form.scriptControl.log(champ.codeName + " Has a lower RMS = " + rms);
                    }
                }
                System.Diagnostics.Debug.WriteLine("champion is " + si.championCodeName);
                sSpell1.Dispose();
                sSpell2.Dispose();
                champImg.Dispose();
                return si;
            }
            catch (Exception e)
            {
                sc.log("[ERROR] (" + e.Source + "): " + e.Message + "\n" + e.StackTrace);
                throw;
            }
        }

    }
}
